package com.qiaofang.service.impl;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.metadata.property.ExcelContentProperty;
import com.alibaba.excel.util.CollectionUtils;
import com.alibaba.excel.util.NumberUtils;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Maps;
import com.qiaofang.common.exception.BusinessException;
import com.qiaofang.common.utils.DateUtil;
import com.qiaofang.common.utils.StringUtil;
import com.qiaofang.constant.*;
import com.qiaofang.entity.*;
import com.qiaofang.repository.CompanyRelationRepository;
import com.qiaofang.repository.CustomerPremisesRepository;
import com.qiaofang.repository.FollowUpRepository;
import com.qiaofang.service.*;
import com.qiaofang.util.BatchReport;
import com.qiaofang.util.BatchReportListener;
import com.qiaofang.util.BatchReportVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.utils.Lists;
import org.apache.commons.compress.utils.Sets;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.math.BigDecimal;
import java.text.ParseException;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Slf4j
@Service
public class BatchServiceImpl implements BatchService {

    @Autowired
    private PremisesService premisesService;

    @Autowired
    private PartnerInfoService partnerInfoService;

    @Autowired
    private CompanyRelationRepository companyRelationRepository;

    @Autowired
    private CustomerPremisesRepository customerPremisesRepository;

    @Autowired
    private DepartmentService departmentService;

    @Autowired
    private FollowUpRepository followUpRepository;

    @Autowired
    private CustomerService customerService;

    private List<BatchReportVO> failList;

    private Long companyId;

    private Date reportDate;

    private String batchUuid;

    @Override
    public void batchReport(MultipartFile file, Long companyId, String reportDate) {
        if (companyId == null) {
            throw new BusinessException("参数异常");
        }
        try {
            failList = Lists.newArrayList();
            this.companyId = companyId;
            this.reportDate = DateUtil.minOfString(reportDate);
            this.batchUuid = UUID.randomUUID().toString();
            log.info("batch report batchUuid: {}", this.batchUuid);
            EasyExcel.read(file.getInputStream(), BatchReport.class, new BatchReportListener()).sheet().headRowNumber(2).doRead();
            if (failList.size() > 0) {
                throw new BusinessException(failList.size() + "条数据导入失败，原因查看表格");
            }
        } catch (IOException ex) {
            log.error("批量导入异常: {}", ex);
            throw new BusinessException("批量导入异常: {}", ex);
        }
    }

    @Override
    public List<BatchReportVO> downloadFailExcel() {
        return failList;
    }

    @Override
    public void batchSaveReport(List<BatchReport> list) {
        //楼盘名字
        Set<String> premisesNameList = Sets.newHashSet();
        //报备人手机号
        Set<String> phoneList = Sets.newHashSet();
        if (list != null) {
            for (int i = list.size() - 1; i >= 0; i--) {
                BatchReport batchReport = list.get(i);
                if (CustomerStatusEnum.checkStatus(batchReport.getReportStatus())) {
                    //数据完整性校验
                    if (StringUtil.isNotBlank(batchReport.getPremisesName())) {
                        premisesNameList.add(batchReport.getPremisesName());
                    } else {
                        list.remove(i);
                        failList.add(convert(batchReport, "楼盘名为空！"));
                    }
                    String partnerPhone = null;
                    if (batchReport.getPartnerPhone() != null) {
                        partnerPhone = batchReport.getPartnerPhone();
                    }
                    if (StringUtil.isNotBlank(partnerPhone)) {
                        phoneList.add(partnerPhone);
                    } else {
                        list.remove(i);
                        failList.add(convert(batchReport, "经纪人手机为空！"));
                    }
                    if (StringUtil.isBlank(batchReport.getCustomerName())) {
                        list.remove(i);
                        failList.add(convert(batchReport, "客户姓名为空！"));
                    }
                    if (batchReport.getCustomerPhone() == null) {
                        list.remove(i);
                        failList.add(convert(batchReport, "客户手机为空！"));
                    }
                    if (StringUtil.isBlank(batchReport.getCustomerSex())) {
                        batchReport.setCustomerSex("男");
                    }
                    ConfirmStatusEnum confirmStatusEnum = ConfirmStatusEnum.getByDesc(batchReport.getTradeStatus());
                    if(Objects.nonNull(confirmStatusEnum)){
                        // 交易状态 >= 认筹,代表已进入交易阶段.判断报备状态是否已到访.若不是.变更报备状态至已到访
                        if (Integer.valueOf(confirmStatusEnum.getNo()) >= Integer.valueOf(ConfirmStatusEnum.payDeposit.getNo())) {
                            batchReport.setReportStatus(CustomerStatusEnum.has_visited.getDes());
                        }
                        if (Integer.valueOf(confirmStatusEnum.getNo()) >= Integer.valueOf(ConfirmStatusEnum.subscribe.getNo())) {
                            //认购
                            if (StringUtil.isBlank(batchReport.getBlock())) {
                                list.remove(i);
                                failList.add(convert(batchReport, "栋座为空！"));
                            }
                            if (StringUtil.isBlank(batchReport.getRoomNo())) {
                                list.remove(i);
                                failList.add(convert(batchReport, "房号为空！"));
                            }
                            if (StringUtil.isBlank(batchReport.getContractPrice())) {
                                list.remove(i);
                                failList.add(convert(batchReport, "签约价格为空！"));
                            }
                        }
                        if(Integer.valueOf(confirmStatusEnum.getNo()) >= Integer.valueOf(ConfirmStatusEnum.sign.getNo()))if (StringUtil.isBlank(batchReport.getAcreage())) {
                            list.remove(i);
                            failList.add(convert(batchReport, "面积为空！"));
                        }
                    }else{
                        batchReport.setTradeStatus(ConfirmStatusEnum.confirm.getNo());
                    }
                } else {
                    list.remove(i);
                    failList.add(convert(batchReport, "报备状态不满足【报备待审、未到访,已到访】!"));
                }
            }
            //查询数据库
            List<String> companyIds = listCompanyId();
            Map<String, Premises> premisesMap = mapPremises(premisesNameList);
            Map<String, PartnerInfo> partnerInfoMap = mapPartnerInfo(phoneList, companyIds);
            Map<String, Long> principalMap = mapPrincipal(partnerInfoMap);
            for (BatchReport batchReport : list) {
                if (!premisesMap.containsKey(batchReport.getPremisesName())) {
                    failList.add(convert(batchReport, "找不到对应楼盘！"));
                    continue;
                }
                if (!partnerInfoMap.containsKey(String.valueOf(batchReport.getPartnerPhone()))) {
                    failList.add(convert(batchReport, "找不到对应经纪人！"));
                    continue;
                }
            }

            if(null == failList || failList.size() ==0){
                for (BatchReport batchReport : list) {
                    CustomerPremises customerPremises = new CustomerPremises();
                    try {
                        CustomerStatusEnum customerStatusEnum = CustomerStatusEnum.getByDesc(batchReport.getReportStatus());
                        ConfirmStatusEnum confirmStatusEnum = ConfirmStatusEnum.getByDesc(batchReport.getTradeStatus());
                        Premises premises = premisesMap.get(batchReport.getPremisesName());
                        PartnerInfo partnerInfo = partnerInfoMap.get(String.valueOf(batchReport.getPartnerPhone()));
                        //写报备tm_customer_premises
                        customerPremises.setStaffId(partnerInfo.getId());
                        customerPremises.setStaffCompanyId(Long.parseLong(partnerInfo.getHigherId()));
                        if (principalMap.containsKey(partnerInfo.getHigherId())) {
                            customerPremises.setPrincipalId(principalMap.get(partnerInfo.getHigherId()));
                        }
                        customerPremises.setCompanyId(companyId);
                        customerPremises.setPremisesId(premises.getId());
                        customerPremises.setMobile(String.valueOf(batchReport.getCustomerPhone()));
                        customerPremises.setName(batchReport.getCustomerName());
                        if (StringUtil.equals("男", batchReport.getCustomerSex())) {
                            customerPremises.setGender("0");
                        } else {
                            customerPremises.setGender("1");
                        }
                        customerPremises.setConfirmStatus(confirmStatusEnum.getNo());
                        customerPremises.setCustomerStatus(customerStatusEnum.getNo());
                        customerPremises.setBuildingName(batchReport.getBlock());
                        customerPremises.setRoomName(batchReport.getRoomNo());
                        customerPremises.setReportType(ReportTypeEnum.type_3.getNo());
                        if(StringUtils.isNotBlank(batchReport.getAcreage())){
                            customerPremises.setValuationArea(new BigDecimal(batchReport.getAcreage()));
                        }
                        if(StringUtils.isNotBlank(batchReport.getContractPrice())){
                            customerPremises.setDealAmount(new BigDecimal(batchReport.getContractPrice()));
                        }
                        if(StringUtils.isNotBlank(batchReport.getVisitTime())){
                            customerPremises.setVisitTime(DateUtils.parseDate(batchReport.getVisitTime(), "yyyy-MM-dd HH:mm:ss"));
                        }
                        if(StringUtils.isNotBlank(batchReport.getDealDate())){
                            if (Integer.valueOf(confirmStatusEnum.getNo()) >= Integer.valueOf(ConfirmStatusEnum.payDeposit.getNo())) {
                                customerPremises.setPayDepositTime(DateUtils.parseDate(batchReport.getDealDate(), "yyyy-MM-dd HH:mm:ss"));
                            }
                            if (Integer.valueOf(confirmStatusEnum.getNo()) >= Integer.valueOf(ConfirmStatusEnum.subscribe.getNo())) {
                                customerPremises.setSubscribeTime(DateUtils.parseDate(batchReport.getDealDate(), "yyyy-MM-dd HH:mm:ss"));
                            }
                            if (Integer.valueOf(confirmStatusEnum.getNo()) >= Integer.valueOf(ConfirmStatusEnum.sign.getNo())) {
                                customerPremises.setSignTime(DateUtils.parseDate(batchReport.getDealDate(), "yyyy-MM-dd HH:mm:ss"));
                            }
                        }
                        if(StringUtils.isNotBlank(batchReport.getReportProtectTime())){
                            customerPremises.setReportPeriodTime(DateUtils.parseDate(batchReport.getReportProtectTime(), "yyyy-MM-dd HH:mm:ss"));
                        }
                        if(StringUtils.isNotBlank(batchReport.getValidTime())){
                            customerPremises.setReportValidTime(DateUtils.parseDate(batchReport.getValidTime(), "yyyy-MM-dd HH:mm:ss"));
                        }
                        if(StringUtils.isNotBlank(batchReport.getVisitProtectTime())){
                            customerPremises.setVisitBaohuTime(DateUtils.parseDate(batchReport.getVisitProtectTime(), "yyyy-MM-dd HH:mm:ss"));
                        }
                        customerPremises.setCreateTime(new Date());
                        customerPremises.setUpdateTime(new Date());
                        if(StringUtils.isNotBlank(batchReport.getCreatedTime())){
                            customerPremises.setCreateTime(DateUtils.parseDate(batchReport.getCreatedTime(), "yyyy-MM-dd HH:mm:ss"));
                            customerPremises.setUpdateTime(DateUtils.parseDate(batchReport.getCreatedTime(), "yyyy-MM-dd HH:mm:ss"));
                        }

                        customerPremises.setRemark("批量导入, 批次: " + batchUuid);
                        customerPremises = customerPremisesRepository.save(customerPremises);

                        // 绑定客户
                        if(Objects.nonNull(customerPremises.getId())){
                             customerService.addReport2BindCustomer(customerPremises);
                        }
                        //写跟进
                        List<FollowUp> followUpList = createFollow(customerPremises, Integer.valueOf(customerStatusEnum.getNo()), Integer.valueOf(confirmStatusEnum.getNo()));
                        followUpRepository.saveAll(followUpList);
                    } catch (NumberFormatException | ParseException ex) {
                        log.info("写入数据库报错!", ex);
                        failList.add(convert(batchReport, "写入报错: " + ex.getMessage()));
                    } catch (Exception ex){
                        log.info("写入数据库报错!", ex);
                        log.info("错误的原始数据: {}", JSONObject.toJSONString(batchReport));
                        failList.add(convert(batchReport, "写入报错: " + ex.getMessage()));
                    }
                }
            }
        }
    }

    private List<String> listCompanyId() {
        List<String> companyIds = Lists.newArrayList();
        companyIds.add(String.valueOf(companyId));
        List<CompanyRelation> list = companyRelationRepository.listCompanyId(companyId);
        if (list != null) {
            for (CompanyRelation companyRelation : list) {
                companyIds.add(String.valueOf(companyRelation.getAgentCompany()));
            }
        }
        return companyIds;
    }

    private List<FollowUp> createFollow(CustomerPremises customerPremises, int customerStatus, int confirmStatus) {
        List<FollowUp> list = Lists.newArrayList();
        //新增报备
        Date newDate = DateUtils.addMinutes(customerPremises.getCreateTime(), 1);
        FollowUp followUp = new FollowUp();
        followUp.setCreateTime(newDate);
        followUp.setCustomerPremisesId(customerPremises.getId());
        followUp.setNewConfirmStatus(ConfirmStatusEnum.confirm.getNo());
        followUp.setNewCustomerStatus(CustomerStatusEnum.normal.getNo());
        followUp.setStaffId(customerPremises.getStaffId());
        followUp.setFollowType(FollowTypeEnum.CHANNEL.getNo());
        followUp.setRemark("【报备客户】导入");
        followUp.setFollowUpType(FollowUpEnum.status_transfer.getNo());
        list.add(followUp);
        if(Integer.valueOf(CustomerStatusEnum.not_visited.getNo()) == customerStatus || Integer.valueOf(CustomerStatusEnum.has_visited.getNo()) == customerStatus){
            //到访审核
            newDate = DateUtils.addMinutes(newDate, 1);
            FollowUp followUp1 = new FollowUp();
            followUp1.setCreateTime(newDate);
            followUp1.setCustomerPremisesId(customerPremises.getId());
            followUp1.setOldConfirmStatus(ConfirmStatusEnum.confirm.getNo());
            followUp1.setNewConfirmStatus(ConfirmStatusEnum.confirm.getNo());
            followUp1.setOldCustomerStatus(CustomerStatusEnum.normal.getNo());
            followUp1.setNewCustomerStatus(CustomerStatusEnum.not_visited.getNo());
            followUp1.setStaffId(customerPremises.getStaffId());
            followUp1.setFollowType(FollowTypeEnum.CHANNEL.getNo());
            followUp1.setRemark("【未到访】导入");
            followUp1.setFollowUpType(FollowUpEnum.status_transfer.getNo());
            list.add(followUp1);
            if(Integer.valueOf(CustomerStatusEnum.has_visited.getNo()) == customerStatus){
                //到访
                newDate = DateUtils.addMinutes(newDate, 1);
                FollowUp followUp2 = new FollowUp();
                followUp2.setCreateTime(newDate);
                followUp2.setCustomerPremisesId(customerPremises.getId());
                followUp2.setOldConfirmStatus(ConfirmStatusEnum.confirm.getNo());
                followUp2.setNewConfirmStatus(ConfirmStatusEnum.confirm.getNo());
                followUp2.setOldCustomerStatus(CustomerStatusEnum.not_visited.getNo());
                followUp2.setNewCustomerStatus(CustomerStatusEnum.has_visited.getNo());
                followUp2.setStaffId(customerPremises.getStaffId());
                followUp2.setFollowType(FollowTypeEnum.CHANNEL.getNo());
                followUp2.setRemark("【已到访】导入");
                followUp2.setFollowUpType(FollowUpEnum.status_transfer.getNo());
                list.add(followUp2);
            }
        }

        if (confirmStatus >= Integer.valueOf(ConfirmStatusEnum.payDeposit.getNo())) {
            //认筹
            newDate = DateUtils.addMinutes(newDate, 1);
            FollowUp followUp3 = new FollowUp();
            followUp3.setCreateTime(newDate);
            followUp3.setCustomerPremisesId(customerPremises.getId());
            followUp3.setOldConfirmStatus(ConfirmStatusEnum.confirm.getNo());
            followUp3.setNewConfirmStatus(ConfirmStatusEnum.payDeposit.getNo());
            followUp3.setOldCustomerStatus(CustomerStatusEnum.has_visited.getNo());
            followUp3.setNewCustomerStatus(CustomerStatusEnum.has_visited.getNo());
            followUp3.setStaffId(customerPremises.getStaffId());
            followUp3.setFollowType(FollowTypeEnum.CHANNEL.getNo());
            followUp3.setRemark("【认筹】导入");
            followUp3.setFollowUpType(FollowUpEnum.status_transfer.getNo());
            list.add(followUp3);
        }
        if (confirmStatus >= Integer.valueOf(ConfirmStatusEnum.payDeposit.getNo())) {
            //认购
            newDate = DateUtils.addMinutes(newDate, 1);
            FollowUp followUp4 = new FollowUp();
            followUp4.setCreateTime(newDate);
            followUp4.setCustomerPremisesId(customerPremises.getId());
            followUp4.setOldConfirmStatus(ConfirmStatusEnum.payDeposit.getNo());
            followUp4.setNewConfirmStatus(ConfirmStatusEnum.subscribe.getNo());
            followUp4.setOldCustomerStatus(CustomerStatusEnum.has_visited.getNo());
            followUp4.setNewCustomerStatus(CustomerStatusEnum.has_visited.getNo());
            followUp4.setStaffId(customerPremises.getStaffId());
            followUp4.setFollowType(FollowTypeEnum.CHANNEL.getNo());
            followUp4.setRemark("【认购】导入");
            followUp4.setFollowUpType(FollowUpEnum.status_transfer.getNo());
            list.add(followUp4);
        }
        if (confirmStatus >= Integer.valueOf(ConfirmStatusEnum.payDeposit.getNo())) {
            //签约
            newDate = DateUtils.addMinutes(newDate, 1);
            FollowUp followUp5 = new FollowUp();
            // 签约报备不会无效化,可直接使用导入提供的时间
            followUp5.setCreateTime(newDate);
            followUp5.setCustomerPremisesId(customerPremises.getId());
            followUp5.setOldConfirmStatus(ConfirmStatusEnum.subscribe.getNo());
            followUp5.setNewConfirmStatus(ConfirmStatusEnum.sign.getNo());
            followUp5.setOldCustomerStatus(CustomerStatusEnum.has_visited.getNo());
            followUp5.setNewCustomerStatus(CustomerStatusEnum.has_visited.getNo());
            followUp5.setStaffId(customerPremises.getStaffId());
            followUp5.setFollowType(FollowTypeEnum.CHANNEL.getNo());
            followUp5.setRemark("【签约】导入");
            followUp5.setFollowUpType(FollowUpEnum.status_transfer.getNo());
            list.add(followUp5);
        }
        // 报备无效 状态带确认
        if(Integer.valueOf(CustomerStatusEnum.no_valid.getNo()) == customerStatus){
            //到访
            newDate = DateUtils.addMinutes(newDate, 1);
            FollowUp followUp2 = new FollowUp();
            followUp2.setCreateTime(newDate);
            followUp2.setCustomerPremisesId(customerPremises.getId());
            followUp2.setOldConfirmStatus(ConfirmStatusEnum.confirm.getNo());
            followUp2.setNewConfirmStatus(ConfirmStatusEnum.confirm.getNo());
            followUp2.setOldCustomerStatus(CustomerStatusEnum.normal.getNo());
            followUp2.setNewCustomerStatus(CustomerStatusEnum.no_valid.getNo());
            followUp2.setStaffId(customerPremises.getStaffId());
            followUp2.setFollowType(FollowTypeEnum.CHANNEL.getNo());
            followUp2.setRemark("【报备无效】导入");
            followUp2.setFollowUpType(FollowUpEnum.status_transfer.getNo());
            list.add(followUp2);
        }
        return list;
    }

    private BatchReportVO convert(BatchReport batchReport, String errorMsg) {
        BatchReportVO vo = new BatchReportVO();
        BeanUtils.copyProperties(batchReport, vo);
        vo.setErrorMsg(errorMsg);
        return vo;
    }

    /**
     * 获取楼盘
     *
     * @param premisesNameList
     * @return
     */
    private Map<String, Premises> mapPremises(Set<String> premisesNameList) {
        List<Premises> premisesList = premisesService.listPremisesByName(premisesNameList, companyId);
        Map<String, Premises> premisesMap = premisesList.parallelStream().collect(Collectors.toMap(Premises::getName, Function.identity()));
        return premisesMap;
    }

    private Map<String, PartnerInfo> mapPartnerInfo(Set<String> phoneList, List<String> companyIds) {
        List<PartnerInfo> partnerInfoList = partnerInfoService.listPartnerInfoByPhone(phoneList, companyIds);
        Map<String, PartnerInfo> partnerInfoMap = partnerInfoList.parallelStream()
                .collect(Collectors.toMap(PartnerInfo::getPhone, Function.identity(),(oldValue, newValue) -> newValue));
        return partnerInfoMap;
    }

    private Map<String, Long> mapPrincipal(Map<String, PartnerInfo> partnerInfoMap) {
        List<Long> companyIds = Lists.newArrayList();
        if (partnerInfoMap != null) {
            for (Map.Entry<String, PartnerInfo> stringPartnerInfoEntry : partnerInfoMap.entrySet()) {
                companyIds.add(Long.parseLong(stringPartnerInfoEntry.getValue().getHigherId()));
            }
        }
        Map<String, Long> principalMap = Maps.newHashMap();
        if(CollectionUtils.isEmpty(companyIds)){
            return principalMap;
        }
        List<Department> departments = departmentService.listTopDepartment(companyIds);
        if (departments != null) {
            for (Department department : departments) {
                principalMap.put(department.getMerchantId().toString(), department.getPrincipal());
            }
        }
        return principalMap;
    }

    public static void main(String[] args) throws ParseException {
        ExcelContentProperty ep = new ExcelContentProperty();
        System.out.println(NumberUtils.parseLong("19957730110", ep));
    }

}
